Self-Quitting CGI

This lesson will teach you how to create a CGI application that will quit after a specified period of inactivity. While there are a number of ways to do this, the method I will show is generic enough to use with almost any script and allows you to do processing on shutdown (if you want to save application settings).

Required OSAX

ScriptTools

NOTE: if you have not yet installed this OSAX, then do it before starting this lesson. The script will not compile without it. Go back to the Requirements section to download the OSAX if you need it.


Script2.txt - A Self-Quitting CGI

Here is the entire script for this lesson. The comments have been removed so you see only the lines that actually get compiled. The full script, including comments and special characters, is in the archive with the name "Script2.txt".
property crlf : (ASCII character 13) & (ASCII character 10)
property http_10_header : "HTTP/1.0 200 OK" & crlf & "Server: WebSTAR/1.0 ID/ACGI" & crlf & ¬
   "MIME-Version: 1.0" & crlf & "Content-type: text/html" & crlf & crlf
property idletime : 1800
property datestamp : 0

set datestamp to current date

on «event WWWΩsdoc» path_args ¬
   given «class kfor»:http_search_args, «class post»:post_args, «class meth»:method, «
      class addr»:client_address, «class user»:username, «class pass»:password, «class frmu»:from_user, «
      class svnm»:server_name, «class svpt»:server_port, «class scnm»:script_name, «
      class ctyp»:content_type, «class refr»:referer, «class Agnt»:user_agent, «
      class Kact»:action, «class Kapt»:action_path, «class Kcip»:client_ip, «class Kfrq»:full_request
	
   set datestamp to current date
	
   set return_page to http_10_header ¬
      & "<HTML><HEAD><TITLE>Unprocessed Results</TITLE></HEAD>" ¬
      & "<BODY><H1>Unprocessed Results</H1>" & return ¬
      & "<H4>path_args</H4>" & return & path_args & return ¬
      & "<H4>http_search_args</H4>" & return & http_search_args
   set return_page to return_page & return ¬
      & "<H4>post_args</H4>" & return & post_args & return ¬
      & "<H4>method</H4>" & return & method & return ¬
      & "<H4>client_address</H4>" & return & client_address & return ¬
      & "<H4>username</H4>" & return & username & return ¬
      & "<H4>password</H4>" & return & password & return
   set return_page to return_page & return ¬
      & "<H4>from_user</H4>" & return & from_user & return ¬
      & "<H4>server_name</H4>" & return & server_name & return ¬
      & "<H4>server_port</H4>" & return & server_port & return ¬
      & "<H4>script_name</H4>" & return & script_name & return ¬
      & "<H4>content_type</H4>" & return & content_type & return ¬
      & "<H4>referer</H4>" & return & referer & return
   set return_page to return_page & return ¬
      & "<H4>user_agent</H4>" & return & user_agent & return ¬
      & "<H4>action</H4>" & return & action & return ¬
      & "<H4>action_path</H4>" & return & action_path & return ¬
      & "<H4>client_ip</H4>" & return & client_ip & return ¬
      & "<H4>full_request</H4>" & return & full_request & return
   set return_page to return_page ¬
      & "<I>Results generated at: " & (current date) ¬
      & "</I>" & "</BODY></HTML>"   return return_page
	
end «event WWWΩsdoc»

on idle
   if (current date) > (datestamp + idletime) then
      quit
   end if
   return 5
end idle

on quit
   continue quit
end quit

Step By Step

Let's take a look at the additions to the script.
   property idletime : 1800
   property datestamp : 0
These are two new properties that are used to control when the CGI will quit itself. idletime tells how long to allow the CGI to remain idle before quitting. It is measured in seconds, so the line above lets the CGI run 30 minutes before quitting. datestamp contains the last date that something happened. As you will see below, it is set at startup and at the start of each Apple event. It is important that these are properties, so their value persists between Apple events received.
   set datestamp to current date
This line gets the current date (which includes day and time) and stores it in the variable datestamp. This line is used twice; once at the very start and once inside the Apple event handler. By putting it outside the Apple event handler, it ensures that the CGI will quit as desired even if it was somehow launched without an Apple event. The line inside the Apple event handler ensures that it will be reset each time an Apple event is processed.
NOTE: Within the Apple event handler, the datestamp is set at the very start. For this reason, your idletime should include the amount of time it will typically take your CGI to process the information. As an example, if your script usually takes one minute to run and you set your idletime to "120" (two minutes), you will actually have only about one minute after the first Apple event is finished before the CGI application will quit (unless another Apple event is sent). You could also solve this problem by moving the "set" statement in the Apple event handler to the end of the script, but that would mean placing a separate "set" statement before every "return" statement, which would be much more unwieldy and more likely to cause errors.
on idle
   if (current date) > (datestamp + idletime) then
      quit
   end if
   return 5
end idle
This new handler is introduced to test whether it is time to quit or not. When "nothing" is happening (meaning, when no Apple events are sent to this CGI), an "idle" event is sent to the CGI. The idle handler checks the current time and compares it to the last set time to see if it has been long enough to quit yet. If so, then it calls the quit handler (see below). If not, then it returns a value that tells how long to wait before checking for idle again (you don't want to tie up the whole cpu checking to see if you're idle!).
on quit
   continue quit
end quit
This new handler allows you to do processing before quitting. This might be useful if you wanted to save some information about the current state, wanted to log when the CGI runs, or anything else you can think of. Logging could be very useful to get an idea of whether your idletime is set too high or too low for the use the CGI is getting. Currently all this does is tell the CGI to go ahead and quit.

Wrap It Up

There is no demonstration page for this script, since you wouldn't be able to see the effects anyway. The lines and handlers introduced here should be easy to paste into any existing AppleScripts that you may have to add this handy feature.

I haven't mentioned yet why you might want to have your script quit. Well, there are a couple of good reasons. One is if you are developing a CGI. Having it quit after a couple of minutes is a good way to make sure that you will be able to overwrite it with an updated version as you make changes. Another reason is for memory management. If your server doesn't have enough memory to keep all of your CGI's running at once (and you don't want to spring for more memory) then this method keeps only those CGI's that are needed in memory. A final reason is "just because you want to." I don't like having 15 or 20 CGI's open all of the time when the majority of them are only used once a day or so. For those that are rarely used, I have them quite between runs.

Now there is the other question: Why not have your CGI's quit? Well, your users will get a much better response from a CGI that is already open and ready to run than from one that has to launch itself first. On some systems that delay may amount to several seconds. In most cases you want to give your user the best performance possible. There is also a possible problem with lost requests. When your CGI quits, there is a period where it is in the process of quitting. During this period it can still receive requests from WebSTAR, but it can't respond to them because it is busy quitting. These requests will be lost if this occurs. Your CGI will take longer to quit if you have any extra commands in the quit handler, or if you have properties that have changed (they have to be saved to disk). The longer it takes to quit, the more likely you are to miss a request. I have set these scripts to quit after 30 minutes. Since it only takes about 3 seconds to quit, that means the odds are pretty low that a request will come right at that moment. The longer you keep the CGI running, the lower the odds are that you will lose a request.

Also, some people are afraid that all that starting and quitting will cause memory fragmentation - that means that your memory is allocated in chunks that are not contiguous, so that your free memory is not available in one large block. This is not the same as disk fragementation. It will not make your computer run any more slowly. In addition, since most CGI's written in AppleScript tend to use the same amount of memory (about 200K), they will be able to fit in the slot they or another CGI left behind. In other words, I don't think this is a worry.

There is one caveat when working with scripts that are self-quitting. You want to be careful not to quit the script before you are done processing all of the Apple events that might be queued up. This is not a problem with regular CGI applications. With the new ability to do asynchronous processing of CGI applications, though, there is the possibility for this to be a problem. For that reason, make sure that idletime is long enough for the Apple event to be processed and another one that is waiting to be accepted.


[Go back to Tutorial Index]

Jon Wiederspan
Last Edited: April 26, 1995
Copyright Jon Wiederspan, 1994,1995